/**
 * \file   directiva.cpp
 * \author Fabian Jesus Machado
 * \date   Septiembre de 2011
 * 
 *  Este archivo es parte del proyecto NPASM, un ensamblador para
 * microcontroladores PIC con sintaxis Intel, desarrollado inicialmente
 * por Fabian Machado (fabianjsm@gmail.com, twitter@fabianjsm).
 *  El codigo fuente esta diponible en el repositorio SVN de Google:
 *      http://npasm.googlecode.com/svn/trunk.
 * 
 */
#include <iostream>
#include <stdio.h>
#include "auxiliar.h"
#include "entorno.h"
#include "directiva.h"
#include "sintaxis.h"

using namespace std;

static FILE *salida_log = stdout;

void drtv_log(int tipo, unsigned long valor)
{
	if(Entorno->GetPaso() != 2)
		return;
	if(tipo == LOG_NUM) {
		fprintf(salida_log, "%lu", valor);
	} else {
		const char *s = "\r\n";
		if(tipo == LOG_STR)
			s = Entorno->TString->GetString(valor).c_str();
		fprintf(salida_log, "%s", s);
	}
}

void drtv_define(simbolo *sbl, unsigned long val)
{
	if(Entorno->GetPaso() == 2)
		return;
	if(sbl->GetTipo() == DEFINE_NUM) {
		const char *s = sbl->GetNombre().c_str();
		size_t ln = Entorno->GetLinea();
		throw(mkstring("Macro '%s' redefinida en linea %d", s, ln));
	}
	sbl->SetTipo(DEFINE_NUM);
	sbl->SetVal((unsigned int)val);
	sbl->SetUcase(true);
	sbl->SetLindef(Entorno->GetLinea());
}


int abrir_include(string archivo, std::vector<include,
	std::allocator<include> > &pila_include)
{
	FILE *f = fopen(archivo.c_str(), "rb");
	if(!f)
		return 0;
	pila_include.push_back(include(yyin, ftell(yyin),
		Entorno->GetLinea(), Entorno->GetNombreArchivoActual()));
	yyin = f;
	yyrestart(yyin);
	Entorno->SetNombreArchivoActual(archivo);
	Entorno->SetLinea(1);
	return 1;
}

/**
 * Esta funcion procesa la directiva include
 * 
 * @param n Indice del nombre de archivo en la tabla de string
 * 
 * @note Su comportamiento es independiente del paso actual.
 * 
 *   str_nombre_base = "../ejemplos/led"
 *   str_dir_base    = "../ejemplos/"
 */
void drtv_include(unsigned long n)
{
	string archivo = Entorno->TString->GetString(n);
	bool a = abrir_include(Entorno->str_dir_base + archivo,
	 Entorno->pila_include);
	if(a)
		return;
	int max = Entorno->str_incdir.size();
	for(int i=0; i<max; i++)
		if(abrir_include(Entorno->str_incdir[i] + archivo,
		 Entorno->pila_include))
			return;
	throw(mkstring("No se puede abrir '%s'\n", archivo.c_str()));
}

int restaurar_include()
{
	size_t n = Entorno->pila_include.size();
	if(!n)
		return 1;
	fclose(yyin);
	include i = Entorno->pila_include[n - 1];
	yyin = i.yyin;
	yyrestart(yyin);
	fseek(yyin, i.seek, SEEK_SET);
	Entorno->SetLinea(i.l);
	Entorno->SetNombreArchivoActual(i.nombre);
	Entorno->pila_include.pop_back();
	return 0;
}

include::include(FILE *_yyin, size_t _seek, size_t _l, string _nombre)
{
	yyin = _yyin;
	seek = _seek;
	l = _l;
	nombre = _nombre;
}
